<template lang="pug">
form.block.form-box(@submit="methods._submit")
  //- 自定义表单头部
  slot(name="beforeItems")
  template(v-for="n,i in items" :key="i")
    //- 完全自定义
    template(v-if="n.type == 'slot'")
      slot(:name="n.name" :label="n.label")
    //- 插入分割线
    template(v-else-if="n.type == 'divider'")
      view.form-divider
    template(v-else)
      view.row.flex.rel(:class="n.name+' '+(n.type||'input')+(n.type=='textarea'?' start':'')")
        view.label(:class="{required: showRequiredPrefix && n.required, unprefix: !showRequiredPrefix}" :hidden="n.un_label") {{n.label}}
        //- 增加右侧内容自定义插槽
        template(v-if="n.type == 'slot-right'")
          view.grow: slot(name="right" :item="n.name" :label="n.label" :placeholder="n.placeholder || `请输入${n.label}`")
        //- switch开关
        template(v-else-if="n.type == 'switch'")
          view.grow
          switch.io(:checked="n.val" :data-k="n.name" @change="methods._action" color="var(--bg-color-red)")
        //- radio选择器
        //- {name: 'gender', label: '性别', type: 'radio', vals: [{title: '男', val: 0}, {title: '女', val: 1}]}
        template(v-else-if="n.type == 'radio'")
          radio-group.grow.flex(@change="methods._action" :data-k="n.name" :data-type="n.type")
            view.grow
            label.a-radio.flex.inline(v-for="nn,ii in n.vals")
              radio.icon(:value="nn.val" :checked="nn.val == n.val" color="var(--bg-color-red)")
              text {{nn.title}}
          input.hidden(:name="n.name" :value="n.val" )
        //- 圆形头像
        template(v-else-if="n.type == 'avatar'")
          view.avatar-box.flex.center.grow
            button.clear(open-type="chooseAvatar" @chooseavatar="methods._avatar")
              aimg.avatar-img.block(:src="n.val || n.placeholder")
              view.m-t-10.small.txt.gray 编辑{{n.label}}
        //- select选择器
        //- {name: 'keyman', label: '是否关键决策人', vals: [{id:1, title:'是'}, {id:0, title:'否'}], type: 'select', key: 'title'}
        template(v-else-if="n.type == 'select'")
          input.hidden(:name="n.name" :value="n.val" )
          picker.select.grow(@change="methods._action" :data-k="n.name" :range="n.vals" :range-key="n.key" :value="n.val || 0" )
            view.after.flex.triangle.down(:class="n.val == void 0?'placeholder':''")
              view.grow {{n.val == void 0? (n.placeholder || `请选择${n.label}`): n.vals[n.val][n.key]}}
        //- multiSelector多列级联选择器,支持2列以上
        //- {
              name: 'depart', label: '单位/部门', type: 'multiSelector', key: 'departName', cols: 2,
              vals: [
                [
                  {id: 1, departName: '单位一', children: [{id: 11, departName: '单位1部门1'}, {id: 12, departName: '单位1部门2'}, {id: 13, departName: '单位1部门3'}]},
                  {id: 2, departName: '单位二', children: [{id: 21, departName: '单位2部门1'}, {id: 22, departName: '单位2部门2'}]}
                ],
                [
                  {id: 11, departName: '单位1部门1'},
                  {id: 12, departName: '单位1部门2'},
                  {id: 13, departName: '单位1部门3'}
                ]
              ]
            }
        template(v-else-if="n.type == 'multiSelector'")
          input.hidden(:name="n.name" :value="n.val" )
          picker.select.grow(mode="multiSelector" :value="n.value" :data-i="i" :range="n.vals" :range-key="n.key" @columnchange="methods.multi._column" @change="methods.multi._change")
            view.after.flex.triangle.down(:class="n.val == void 0?'placeholder':''")
              view.grow {{n.val == void 0? (n.placeholder || `请选择${n.label}`): n.val}}
        //- 区域选择器，H5无效
        template(v-else-if="n.type == 'region-picker'")
          // #ifdef MP
          picker.picker.grow(mode="region" :data-k="n.name" @change="methods._action" :value="n.val || []")
            view.arrow.down(:class="n.val?'':'placeholder'") {{n.val?[n.val].join(','):`请选择${n.label}`}}
          // #endif
        //- 日期选择器
        template(v-else-if="n.type == 'date-picker'")
          picker.grow(mode="date" :value="n.val || ''" @change="methods._action" :data-k="n.name")
            view.after.flex.triangle.down(:class="n.val == void 0?'placeholder':''")
              view.grow {{n.val == void 0? (n.placeholder || `请选择${n.label}`): n.val}}
        //- 文本域
        template(v-else-if="n.type == 'textarea'")
          view.grow.rel
            textarea.textarea(
             :name="n.name"
             :data-k="n.name"
             :placeholder="n.placeholder || `请输入${n.label}`"
             :maxlength="n.maxlength || -1"
             placeholder-class="placeholder"
             :value="n.val || ''"
             @input="methods._action")
            view.abs.txt.gray(v-if="n.maxlength && n.show_length") {{n.len || 0}}/{{n.maxlength}}
        //- 文本框等其他表单项
        template(v-else)
          view.grow.rel
            input.input(
             :name="n.name"
             :data-k="n.name"
             :placeholder="n.placeholder || `请输入${n.label}`"
             :maxlength="n.maxlength || -1"
             placeholder-class="placeholder"
             :type="n.type || 'input'"
             :value="n.val || ''"
             @input="methods._action")
            view.abs.txt.gray(v-if="n.maxlength && n.show_length") {{n.len || 0}}/{{n.maxlength}}
          //- 支持在内容右侧自定义插槽
          slot(:name="n.name")
  //- 自定义表单底部
  slot(name="beforeBtns")
  view.btns.mod.bsbb.m-auto.flex
    button.clear.btn.submit.linear(form-type="submit") {{submitBtn||'提交'}}
    template(v-if="hasResetBtn")
      view.m-r-12
      button.clear.btn.plain.submit(@click="methods._reset") 重置
</template>
<script setup>
import {_feedback} from '/common/script/tip'
import {__postImage} from '/common/script/req.promise'

const props = defineProps({
  items: Array,
  submit: Function,// 必须是一个Promise函数
  beforeSubmit: Function, // 提交前执行，返回true|false
  submitBtn: String,
  showRequiredPrefix: {type: Boolean, default: true},
  hasResetBtn: {type: Boolean, default: true}
})
let postData = {} //最终提交的数据
const methods = {
  validate(){
    let flag = true
    props.items.forEach((n,i)=>{
      if(flag){
        if(n.name!=undefined && postData[n.name]==undefined && n.val!=undefined) postData[n.name] = n.val
        if(n.required){
          if(flag = _feedback(postData[n.name]==undefined || !postData[n.name].length, `${n.label}不能为空！`)){
            if(n.pattern){
              flag = _feedback(typeof n.pattern == 'object'? n.pattern: postData[n.name], `${n.label}填写错误！`, n.pattern)
            }
          }
        }
      }
    })
    return flag
  },
  _submit(e){
    uni.showLoading({title: '提交中..', mask: true})
    postData = e.detail.value
    let flag = props.beforeSubmit? props.beforeSubmit(): true
    if(flag &&methods.validate()){
      try{
        props.submit(postData).then(uni.hideLoading)
      }catch(e){ console.log('props.submit的绑定函数必须是Promise', e) }
    }else{
      uni.hideLoading()
    }
  },
  _reset(){
    props.items.forEach((n)=>n.val = void 0)
    const _postData = Object.fromEntries(props.items.map(n=>[n.name, '']))
    props.submit(_postData)
  },
  _action(e){
    const {currentTarget: {dataset: {k}}, detail: {value}} = e
    const i = props.items.findIndex((n)=>n.name == k)
    switch(e.type){
      case 'change':
        props.items[i].val = Array.isArray(value)?value.join(','):value
      break; case 'input':
      // #ifdef APP-PLUS
      case 'onInput':
      // #endif
        props.items[i].len = value.length
      break; case 'onChange':
        props.items[i].val = value
      break;
    }
  },
  _avatar(e){
    const {avatarUrl: path} = e.detail
    __postImage(path).then(src=>{
      const i = props.items.findIndex(n=>n.type=='avatar')
      props.items[i].val = src
    })
  },
  multi:{
    _column(e){
      const {detail: {column,  value}, currentTarget: {dataset: {i}}} = e
      const {cols, vals} = props.items[i]
      if(cols - 1 > column){
        props.items[i].vals[column+1] = vals[column][value].children
        const itemValue = Array(cols).fill(0)
        itemValue[column] = value
        itemValue[column+1] = 0
        props.items[i].value = itemValue
      }
    },
    _change(e){
      const {detail: {value}, currentTarget: {dataset: {i}}} = e
      const {vals, key} = props.items[i]
      props.items[i].val = value.map((i,index)=>vals[index][i][key]).join('-')
    },
  }
}
</script>
<style lang="scss" scoped>
@use '~@/common/scss/mixin.scss' as *;
.form-box{
  .form-divider{
    height: var(--divider-height, 12px);
    @include bg(var(--divider-bgcolor, transparent));
    &+.row{--divider-bgcolor: transparent;}
  }
  .row, :slotted(.row){
    padding: var(--form-box-row-padding, 0 20rpx);
    @include bg(var(--form-box-row-bgcolor, #ffffff));
    .label{
      width: var(--form-box-label-width, 100px);
      font-weight: var(--form-box-label-font-weight, 500);
      color: var(--form-box-label-color, inherit);
      &:not(.unprefix):before{content: ""; width: 10px; display: inline-block;}
      &.required:before{
        content: "*"; 
        color: #EC422A;
      }
    }
    &:not(:first-child){
      border-top: 1px solid var(--divider-bgcolor, #f0f0f0);
    }
    &.start .label{
      margin-top: -2px;
    }
    &.avatar{
      --aimg-border-radius: 50%;
      --aimg-width: 85px;
      --form-box-row-item-padding: 0;
      margin-bottom: 35px;
      .label{display: none;}
      .avatar-img{
        padding: 8px; margin: 0 auto;
        border-radius: var(--aimg-border-radius);
        border:1px solid var(--divider-bgcolor, #f0f0f0);
      }
      & + .row{
        border-top: none;
      }
    }
  }
  .textarea:not(.flex){
    line-height: 1.6;
    height: var(--form-box-textarea-height, 45px);
    width: auto;
  }
  .btns{
    position: var(--form-box-btns-position, relative);
    background-color: var(--form-box-btns-bgcolor, #fff);
    left: 0; bottom: 0;
  }
  .textarea,.input{
    &+.abs{
      right: 0;
      bottom: -5px;
      font-size: 10px;
    }
  }
  .radio{
    .a-radio{margin-left: 24px; padding-left: 12px;}
    .icon{transform:scale(0.7)}
  }
  .switch .io{ transform: scale(0.8); }
  input.hidden{
    width: 0px!important;
    height:1rpx!important;
    min-height:1rpx!important;
    visibility: hidden;
  }
  .label + .grow{
    [class]:nth-child(1){
      // background: red
      padding: var(--form-box-row-item-padding, 25rpx 0);
    }
  }
}
</style>